import * as FileSystem from "expo-file-system";
import * as MediaLibrary from "expo-media-library";
import SystemUtils from "@/utils/system-utils";
import { File, FileType } from "@/types/file-upload";
import {
  createFileCache,
  getFileCacheByMd5,
  updateFileCacheServerUrlById,
} from "@/services/sqlite/file-cache";
import {
  EMOJIS_DATA_SAVE_PATH_PREFIX,
  FILE_DATA_SAVE_PATH_PREFIX,
} from "@/constants/storage";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as VideoThumbnails from "expo-video-thumbnails";
// import * as Crypto from 'expo-crypto';
import { ResponseCode } from "@/types/api-common";

/**
 * 获取文件扩展名（不带点），支持文件名或URL
 * @param filePath 文件名或链接
 * @returns 扩展名字符串（无点），无扩展名返回空字符串
 */
export function getFileExtension(filePath: string): string {
  const lastPart = filePath.split("?")[0].split("#")[0]; // 去除查询和锚点
  const point = lastPart.lastIndexOf(".");
  return point !== -1 ? lastPart.substring(point + 1).toLowerCase() : "";
}

/**
 * 保存文件到相册
 * @param saveFileUri 要保存的文件内容，Base64 编码字符串
 * @returns Promise<void>
 */
export async function saveFileToGallery(saveFileUri: string): Promise<void> {
  if (!saveFileUri) {
    SystemUtils.showSystemAlert("没有可保存的文件内容");
    return;
  }
  try {
    const fileUri = FileSystem.cacheDirectory + `qrcode-${Date.now()}.png`;
    await FileSystem.writeAsStringAsync(fileUri, saveFileUri, {
      encoding: FileSystem.EncodingType.Base64,
    });
    const { status } = await MediaLibrary.requestPermissionsAsync();
    if (status === "granted") {
      await MediaLibrary.saveToLibraryAsync(fileUri);
      SystemUtils.showSystemAlert("文件已保存到相册");
    } else {
      SystemUtils.showSystemAlert("请允许应用访问相册权限以保存文件");
    }
  } catch (e) {
    SystemUtils.showSystemAlert("保存文件到相册失败，请稍后重试");
  }
}

/**
 * 获取文件类型
 * @param file
 */
export function getFileType(file: File): FileType {
  const mimeType = file.type;
  if (mimeType.startsWith("image/")) {
    return FileType.IMAGE;
  } else if (mimeType.startsWith("video/")) {
    return FileType.VIDEO;
  } else if (mimeType.startsWith("audio/")) {
    return FileType.AUDIO;
  } else {
    return FileType.FILE; // 默认文件类型
  }
}

/**
 * 获取文件简单描述
 * @param fileName
 * @param fileType
 */
export function getFileSimpleDescription(
  fileName: string,
  fileType: FileType
): string {
  switch (fileType) {
    case FileType.IMAGE:
      return "[图片]";
    case FileType.VIDEO:
      return "[视频]";
    case FileType.AUDIO:
      return "[音频]";
    default:
      return `[文件] ${fileName}`;
  }
}

/**
 * 获取文件类型英文描述
 * @param fileType
 */
export function getFileTypeEnglishDescription(fileType: FileType): string {
  switch (fileType) {
    case FileType.IMAGE:
      return "image";
    case FileType.VIDEO:
      return "video";
    case FileType.AUDIO:
      return "audio";
    default:
      return "document";
  }
}

/**
 * 计算文件的 MD5 哈希值
 * @param filePath
 */
// export async function getFileMD5(filePath: string): Promise<string> {
//   try {
//     const fileBuffer = await FileSystem.readAsStringAsync(filePath, {
//       encoding: FileSystem.EncodingType.Base64,
//     });
//     // return await Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.MD5, fileBuffer);
//   } catch (error) {
//     console.error("计算文件 MD5 失败:", error);
//     throw error;
//   }
// }

// 视频缩略图生成结果类型
type VideoThumbnailResult = {
  uri: string; // 缩略图的本地路径
  regenerated: boolean; // 是否重新生成了缩略图
};

/**
 * 生成视频缩略图
 * @param messageId
 * @param fileUrl
 * @return {Promise<string | null>} 返回缩略图的本地路径或 null
 */
export async function generateVideoThumbnail(
  messageId: string,
  fileUrl: string
): Promise<VideoThumbnailResult | null> {
  try {
    // 检查缓存中是否已有缩略图
    const cachedThumbnail = await AsyncStorage.getItem(
      `thumbnail_${messageId}`
    );
    const fileInfo = cachedThumbnail
      ? await FileSystem.getInfoAsync(cachedThumbnail)
      : { exists: false };
    if (cachedThumbnail && fileInfo.exists) {
      return {
        uri: cachedThumbnail,
        regenerated: false, // 缓存中已有缩略图，不需要重新生成
      };
    }
    // 清理无效缓存
    await AsyncStorage.removeItem(`thumbnail_${messageId}`);
    // 如果没有缓存，则生成新缩略图
    const { uri } = await VideoThumbnails.getThumbnailAsync(fileUrl, {
      time: 0,
    });
    // 将新生成的缩略图存入缓存
    await AsyncStorage.setItem(`thumbnail_${messageId}`, uri);
    return {
      uri,
      regenerated: true, // 新生成的缩略图
    };
  } catch (error) {
    console.error("生成视频缩略图失败:", error);
    return null;
  }
}

// 文件缓存锁
const lock = new Map<string, Promise<void>>();

/**
 * 缓存文件
 * @param file 要缓存的文件对象
 * @returns 缓存后的本地文件路径或 null
 */
export async function cacheFile(file: File): Promise<string | null> {
  const lockKey = file.md5; // 使用文件的 MD5 作为锁的唯一标识

  while (lock.has(lockKey)) {
    console.warn("文件正在处理中，等待锁释放:", lockKey);
    await lock.get(lockKey); // 等待锁释放
  }

  let resolveLock: () => void;
  const lockPromise = new Promise<void>((resolve) => {
    resolveLock = resolve;
  });
  lock.set(lockKey, lockPromise); // 加锁

  try {
    // 检查文件是否已缓存
    const existingCache = await getFileCacheByMd5(file.md5);
    if (existingCache) {
      console.log("文件已存在于缓存中:", existingCache.filePath);
      return existingCache.filePath;
    }

    // 创建缓存目录并下载文件
    const fileType = getFileType(file);
    const fileDir = `${
      FileSystem.documentDirectory
    }${FILE_DATA_SAVE_PATH_PREFIX}${getFileTypeEnglishDescription(fileType)}`;
    await FileSystem.makeDirectoryAsync(fileDir, { intermediates: true });
    const fileExt = getFileExtension(file.fileName);
    const localFilePath = `${fileDir}/${file.md5}.${fileExt}`;
    await FileSystem.copyAsync({
      from: file.uri,
      to: localFilePath,
    });
    // 缓存文件信息
    await createFileCache({
      filePath: localFilePath,
      serverUrl: "",
      fileMd5: file.md5,
      fileType,
      fileSize: file.size,
    });
    // const downloadResult = await FileSystem.downloadAsync(file.uri, localFilePath);
    //
    // if (downloadResult.status === ResponseCode.SUCCESS) {
    //     const fileInfoResult = await FileSystem.getInfoAsync(file.uri, {size: true});
    //     if (fileInfoResult.exists) {
    //         // 缓存文件信息
    //         await createFileCache({
    //             filePath: localFilePath, serverUrl: "",
    //             fileMd5: file.md5,
    //             fileType,
    //             fileSize: file.size
    //         });
    //         return localFilePath;
    //     }
    // }
    return localFilePath;
  } catch (error) {
    console.error("媒体消息处理失败:", error);
    return null;
  } finally {
    lock.delete(lockKey); // 解锁
    resolveLock!(); // 释放阻塞
  }
}

/**
 * 缓存图片文件
 * @param fileUri 要缓存的文件对象Uri
 * @param serverUrl 服务器文件URL
 * @returns 缓存后的本地文件路径或 null
 */
export async function cacheImageByUri(
  fileUri: string,
  serverUrl: string
): Promise<string | null> {
  const md5 = await getFileMD5(fileUri);
  const lockKey = md5; // 使用文件的 MD5 作为锁的唯一标识

  while (lock.has(lockKey)) {
    console.warn("文件正在处理中，等待锁释放:", lockKey);
    await lock.get(lockKey); // 等待锁释放
  }

  let resolveLock: () => void;
  const lockPromise = new Promise<void>((resolve) => {
    resolveLock = resolve;
  });
  lock.set(lockKey, lockPromise); // 加锁

  try {
    // 检查文件是否已缓存
    const existingCache = await getFileCacheByMd5(md5);
    if (existingCache) {
      console.log("文件已存在于缓存中:", existingCache.filePath);
      return existingCache.filePath;
    }

    // 创建缓存目录并下载文件
    const fileType = FileType.IMAGE;
    const fileDir = `${
      FileSystem.documentDirectory
    }${FILE_DATA_SAVE_PATH_PREFIX}${getFileTypeEnglishDescription(fileType)}`;
    await FileSystem.makeDirectoryAsync(fileDir, { intermediates: true });
    const fileExt = getFileExtension(fileUri);
    const localFilePath = `${fileDir}/${md5}.${fileExt}`;
    console.log("localFilePath = ", localFilePath);

    await FileSystem.copyAsync({
      from: fileUri,
      to: localFilePath,
    });
    const fileInfo = await FileSystem.getInfoAsync(fileUri, { size: true });
    if (!fileInfo.exists) {
      console.error("文件不存在:", fileUri);
      return null;
    }
    const fileSize = fileInfo.size; // 文件大小（以字节为单位）
    // 缓存文件信息
    await createFileCache({
      filePath: localFilePath,
      serverUrl,
      fileMd5: md5,
      fileType,
      fileSize: fileSize,
    });
    return localFilePath;
  } catch (error) {
    console.error("媒体消息处理失败:", error);
    return null;
  } finally {
    lock.delete(lockKey); // 解锁
    resolveLock!(); // 释放阻塞
  }
}

/**
 * 缓存表情包文件
 * @param fileUrl 要缓存的文件 URL
 * @returns 缓存后的本地文件路径或 null
 */
export async function cacheEmoji(fileUrl: string): Promise<string | null> {
  const ext = getFileExtension(fileUrl);
  const filePath = `${
    FileSystem.documentDirectory
  }${EMOJIS_DATA_SAVE_PATH_PREFIX}/${Date.now()}_${Math.random()
    .toString(36)
    .substring(2, 8)}.${ext}`;
  try {
    // 确保目录存在
    await FileSystem.makeDirectoryAsync(
      `${FileSystem.documentDirectory}${EMOJIS_DATA_SAVE_PATH_PREFIX}`,
      { intermediates: true }
    );
    // 下载文件到本地
    const downloadResult = await FileSystem.downloadAsync(fileUrl, filePath);
    if (downloadResult.status === ResponseCode.SUCCESS) {
      return filePath;
    } else {
      console.error("下载文件失败，状态码:", downloadResult.status);
      return null;
    }
  } catch (error) {
    console.error("缓存表情失败:", error);
    return null;
  }
}

/**
 * 删除缓存的表情文件
 * @param filePath 要删除的表情文件路径
 * @returns Promise<void>
 */
export async function removeCacheEmoji(filePath: string): Promise<void> {
  try {
    const fileInfo = await FileSystem.getInfoAsync(filePath);
    if (fileInfo.exists) {
      await FileSystem.deleteAsync(filePath, { idempotent: true });
      console.log("表情缓存已删除:", filePath);
    } else {
      console.warn("要删除的表情缓存不存在:", filePath);
    }
  } catch (error) {
    console.error("删除表情缓存失败:", error);
  }
}

export async function clearFileCache(): Promise<void> {
  try {
    const cacheDir = `${FileSystem.documentDirectory}${FILE_DATA_SAVE_PATH_PREFIX}`;
    const dirInfo = await FileSystem.getInfoAsync(cacheDir);
    if (dirInfo.exists && dirInfo.isDirectory) {
      await FileSystem.deleteAsync(cacheDir, { idempotent: true });
      console.log("文件缓存已清除");
    } else {
      console.warn("文件缓存目录不存在或不是目录:", cacheDir);
    }
  } catch (error) {
    console.error("清除文件缓存失败:", error);
  }
}

export async function updateFileCacheServerUrl(
  fileMd5: string,
  serverUrl: string
): Promise<void> {
  try {
    const existingCache = await getFileCacheByMd5(fileMd5);
    if (existingCache) {
      existingCache.serverUrl = serverUrl;
      await updateFileCacheServerUrlById(existingCache); // 更新缓存
      console.log("文件缓存服务器地址已更新:", fileMd5, serverUrl);
    } else {
      console.warn("未找到要更新的文件缓存:", fileMd5);
    }
  } catch (error) {
    console.error("更新文件缓存服务器地址失败:", error);
  }
}
